/*
 * 文件名： CiticVerifyUtil.java
 * 
 * 工程名称: bis-bank-citic
 *
 * Gopay
 *
 * 创建日期： 2016年7月5日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.citic.expay.operation;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lsy.baselib.crypto.algorithm.DESede;
import com.lsy.baselib.crypto.algorithm.RSA;
import com.lsy.baselib.crypto.protocol.PKCS7Signature;
import com.lsy.baselib.crypto.util.Base64;
import com.lsy.baselib.crypto.util.CryptUtil;
import com.lsy.baselib.crypto.util.FileUtil;

/**
 * 
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年7月5日
 */
public class CiticVerifyUtil {
	/**
	 * 日志对象
	 */
	private static Logger logger = LoggerFactory.getLogger(CiticVerifyUtil.class);

	public static byte[] LinkByteArrays(byte[] arr1, byte[] arr2) {
		int n1 = arr1.length;
		int n2 = arr2.length;
		byte[] newArr = new byte[n1 + n2];
		System.arraycopy(arr1, 0, newArr, 0, n1);
		System.arraycopy(arr2, 0, newArr, n1, n2);
		return newArr;
	}

	/**
	 * 
	 * 功能描述：1）接收方从接收的报文中解析得到会话密钥密文K,使用自己的私钥对会话密钥密文K进行RSA解密，得到会话密钥明文R
	 * 2）使用3DES算法(CBC模式)和密钥R对2进制密文M进行解密，正常应得到加密前的拼接数据“<signature>签名S</signature>
	 * +明文报文X” 3）使用发送方的公钥对签名S和明文报文X进行验证。
	 *
	 * 
	 * @param byte_message
	 *            报文
	 * @param privateFilePwd
	 *            私钥密码
	 * @param privateFileName
	 *            私钥文件名
	 * @param sendPublicCer
	 *            发送方公钥证书名称
	 * @return
	 * 
	 * @author 宣广海
	 * @throws Exception 
	 *
	 * @since 2016年7月5日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	public static byte[] decrypt_verify(byte[] byte_message, String privateFilePwd, String privateFileName,
			String sendPublicCer) throws Exception {
		try {
//			logger.error("byte_message：" + new String(byte_message));
//			logger.error("privateFilePwd：" + privateFilePwd);
//			logger.error("privateFileName：" + privateFileName);
//			logger.error("sendPublicCer：" + sendPublicCer);
			byte[] byte_MsgHead1 = new byte[6]; // 6字节报文头，后续信息长度
			byte[] byte_MsgHead2 = new byte[10]; // 10字节报文头，标识位(P=明文，E=密文)和保留域
			System.arraycopy(byte_message, 0, byte_MsgHead1, 0, 6);
			System.arraycopy(byte_message, 6, byte_MsgHead2, 0, 10);

			int bodyLen = Integer.valueOf(new String(byte_MsgHead1)) - 10;
			byte[] byte_signMessage = new byte[bodyLen];
			System.arraycopy(byte_message, 16, byte_signMessage, 0, bodyLen);

			byte[] byte_plainMessage = null;
			if (byte_MsgHead2[0] != 'E') {
				byte_plainMessage = byte_signMessage; // 明文
			} else {
				// 密文处理
				String sMsg = new String(byte_signMessage);
				String sKey = null;
				String openTag = "<sessionkey>";
				String closeTag = "</sessionkey>";
				byte[] byte_signData = null;

				int start = sMsg.indexOf(openTag);
				if (start != -1) {
					int end = sMsg.indexOf(closeTag, start + openTag.length());
					if (end != -1) {
						sKey = sMsg.substring(start + openTag.length(), end);
						byte_signData = new byte[byte_signMessage.length - end - closeTag.length()];
						System.arraycopy(byte_signMessage, end + closeTag.length(), byte_signData, 0,
								byte_signMessage.length - end - closeTag.length());
					} else {
						logger.error("找不到结束标签：" + closeTag);
						throw new Exception("验签找不到结束标签");
					}
				} else {
					logger.error("找不到开始标签：" + openTag);
					throw new Exception("验签找不到开始标签");
				}

				char[] recverPrivKeyPass = new String(privateFilePwd).toCharArray();
				byte[] base64EncodedPrivatekey = FileUtil.read4file(privateFileName);
				PrivateKey recverPrivKey = CryptUtil.decryptPrivateKey(Base64.decode(base64EncodedPrivatekey),
						recverPrivKeyPass); // 接收方私钥
				byte[] byte_oneMessage = RSA.decrypt(Base64.decode(sKey.getBytes()), recverPrivKey.getEncoded());
				byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
				byte_plainMessage = DESede.decrypt(byte_signData, byte_oneMessage, iv);
			}

			String sData = new String(byte_plainMessage);
			String b64StrSign = null;
			String openTag2 = "<signature>";
			String closeTag2 = "</signature>";
			byte[] plainMessage = null;
			boolean verifyFlag =false;
			int start2 = sData.indexOf(openTag2);
			if (start2 != -1) {
				int end2 = sData.indexOf(closeTag2, start2 + openTag2.length());
				if (end2 != -1) {
					b64StrSign = sData.substring(start2 + openTag2.length(), end2);
					plainMessage = new byte[byte_plainMessage.length - end2 - closeTag2.length()];
					System.arraycopy(byte_plainMessage, end2 + closeTag2.length(), plainMessage, 0,
							byte_plainMessage.length - end2 - closeTag2.length());
				} else {
					logger.error("找不到签名结束标签：" + closeTag2);
					throw new Exception("验签找不到签名结束标签");
				}
			} else {
				logger.error("找不到签名开始标签：" + openTag2 + ", 无签名信息，无法验证签名！");
				throw new Exception("找不到签名开始标签：" + openTag2 + ", 无签名信息，无法验证签名！");
			}

			byte[] base64EncodedSenderCert = FileUtil.read4file(sendPublicCer);
			X509Certificate signerCertificate = CryptUtil
					.generateX509Certificate(Base64.decode(base64EncodedSenderCert));
			PublicKey senderPubKey = signerCertificate.getPublicKey();
			verifyFlag= PKCS7Signature.verifyDetachedSignature(plainMessage,
					Base64.decode(b64StrSign.getBytes()), senderPubKey);

			if(verifyFlag){
				return plainMessage;
			}
		} catch (Exception e) {
			throw new Exception(e);
		}
		return null;
	}

}
